/***
 * Copyright (c) 2021-2031 murenchao
 * fig is licensed under Mulan PubL v2.
 * You can use this software according to the terms and conditions of the Mulan PubL v2.
 * You may obtain a copy of Mulan PubL v2 at:
 *       http://license.coscl.org.cn/MulanPubL-2.0
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PubL v2 for more details.
 */
package cool.taomu.software.fig.rpc

import cool.taomu.software.fig.classloader.FigClassLoaderManage
import cool.taomu.software.fig.classloader.FigClassLoaderManage.Autowired
import cool.taomu.software.fig.configure.ConfigureManage
import io.netty.bootstrap.ServerBootstrap
import io.netty.channel.Channel
import io.netty.channel.ChannelInboundHandlerAdapter
import io.netty.channel.ChannelInitializer
import io.netty.channel.nio.NioEventLoopGroup
import io.netty.channel.socket.nio.NioServerSocketChannel
import io.netty.handler.codec.LengthFieldBasedFrameDecoder
import io.netty.handler.codec.LengthFieldPrepender
import io.netty.handler.codec.string.StringDecoder
import io.netty.handler.codec.string.StringEncoder
import io.netty.util.CharsetUtil
import org.slf4j.LoggerFactory

class RpcServer {
    val LOG = LoggerFactory.getLogger(RpcServer);
    var NioEventLoopGroup selectGroup;
    var NioEventLoopGroup ioGroup;

    @Autowired(RpcServerHandler)
    var ChannelInboundHandlerAdapter handler;

    new() {
        var coreNumber = Runtime.getRuntime().availableProcessors();
        selectGroup = new NioEventLoopGroup(coreNumber);
        ioGroup = new NioEventLoopGroup(coreNumber * 2);
    }

    def startRpcServer() {
        var serverBootstrap = new ServerBootstrap();
        serverBootstrap = serverBootstrap.group(selectGroup, ioGroup);
        serverBootstrap = serverBootstrap.channel(NioServerSocketChannel)
        serverBootstrap.childHandler(new ChannelInitializer<Channel>() {
            override protected initChannel(Channel ch) throws Exception {
                var pipeline = ch.pipeline();
                pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
                pipeline.addLast("frameEncoder", new LengthFieldPrepender(4));
                pipeline.addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
                pipeline.addLast("encoder", new StringEncoder(CharsetUtil.UTF_8))
                pipeline.addLast("handler", handler);
            }
        })
        Runtime.runtime.addShutdownHook(new Thread() {
            override run() {
                selectGroup.shutdownGracefully();
                ioGroup.shutdownGracefully();
            }
        })
        var config = ConfigureManage.loadConfig;
        LOG.info("启动RPC服务 ip: {} port: {}", config.rpc.ip, config.rpc.port);
        var f = serverBootstrap.bind(config.rpc.ip, config.rpc.port).sync();
        f.channel().closeFuture().sync();
    }

    def static start() {
        var fig = new FigClassLoaderManage();
        var rpc = fig.getBean(RpcServer) as RpcServer;
        rpc.startRpcServer();
    }
}
